home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / SAT 2.3.8 / Demos / HeartQuest demo ƒ / gameWindow.p < prev    next >
Text File  |  1996-05-23  |  23KB  |  755 lines

  1. {================================================}
  2. {=============== Game window handler ================}
  3. {================================================}
  4.  
  5. { Example file for Ingemars Sprite Animation Toolkit. }
  6. { © Ingemar Ragnemalm 1992-1994 }
  7. { See doc files for legal terms for using this code. }
  8.  
  9. { This file holds the game window and game menu handlers for HeartQuest.}
  10. { This is where most game-specific code goes, except for the code describing}
  11. { each object. }
  12.  
  13. { GameWindInit is called to initialize, which initializes the window and installs}
  14. {handler procedures (note that menus are installed in main.p). It calls the routines}
  15. {to initialize offscreen GrafPorts and all the animated objects. }
  16.  
  17. { When the user selects New Game, StartGame is called to set up a new}
  18. { game, and then MoveIt, the game driver routine is called. }
  19.  
  20. unit GameWindow;
  21.  
  22. interface
  23.  
  24.     uses
  25. {$IFC UNDEFINED THINK_PASCAL}
  26.         Types, Quickdraw, Resources, ToolUtils, Events, QuickDrawText,{}
  27.         Menus, Windows,
  28. {$ELSEC}
  29.         InterfacesUI, 
  30. {$ENDC}
  31.         TransSkel, SAT, {}
  32.         GameGlobals, sPlayer, sFlypaper, sHeart, sBonus, sPoints, scores, SoundConst, Sound, ClutFade;
  33.  
  34.     procedure DoGameMenu (item: integer);
  35.     procedure GameWindInit;
  36.     procedure DoGameOver;
  37.     procedure InitSprites;
  38.     procedure DrawBackground;
  39.     procedure HQRedraw;
  40.  
  41.  
  42. implementation
  43.  
  44. {var}
  45. {mp: MonsterPtr; { Bra att ha en global tillgänglig. Dvs praktiskt... }
  46. {    SlemtorksHandlerPtr: ProcPtr;}
  47.  
  48.     procedure InitSprites;
  49.     begin
  50. { Call the init routines for each the sprite unit! Don't forget this! }
  51.         InitFlypaper;
  52.         InitHeart;
  53.         InitPlayer;
  54.         InitBonus;
  55.         InitPoints;
  56.     end;
  57.  
  58.  
  59. { Setup a bonus level. This is called when a level finishes and all bonus objects were collected.}
  60.     procedure SetupBonusLevel (level: integer);
  61.         var
  62.             p: point;
  63.             i: integer;
  64.             mp: SpritePtr;
  65.             r: rect;
  66.             s: Str255;
  67.             er: EventRecord; {For EventAvail}
  68.             strwidth: integer;
  69.  
  70.     begin { SetupBonusLevel }
  71.  
  72.         SATSoundPlay(drringH, 10, false);
  73. {SATSoundEvents; Not needed since we call SATRun soon.}
  74.  
  75. { Clear the sprite list }
  76.         while gSAT.sRoot <> nil do
  77.             SATKillSprite(gSAT.sRoot);
  78.  
  79.         bonusLevelRunning := true;
  80.  
  81. { Create all the sprites for the level, depending on the level number. }
  82.  
  83. {batchCount := level * 2 + 10;}
  84.         for i := 1 to level * 2 + 10 do
  85.             mp := SATNewSprite(-2, SATRand(gSAT.offSizeH - 112) + 17, -SATRand(400 + 25 * level), @SetupBonusHeart);
  86.  
  87. { Reposition mouse to the center of the game area. }
  88.         p.h := 256;
  89.         p.v := 171;
  90.         SATSetMouse(p);
  91. { Make the player sprite. }
  92.         mp := SATNewSprite(2, (gSAT.offSizeH - xsize) div 2, gSAT.offSizeV div 2, @SetupPlayer);
  93. { Copy gSAT.backScreen to gSAT.offScreen to erase old sprites. }
  94.         CopyBits(gSAT.backScreen.port^.portBits, gSAT.offScreen.port^.portBits, gSAT.offScreen.port^.portRect, gSAT.offScreen.port^.portRect, srcCopy, nil);
  95.         HQRedraw; {replaces the following out-commented lines:}
  96.  
  97.         AddScore(0);
  98. { Do one frame of animation just to draw all the objects. }
  99.         SATRun(false); {false or features^^.PlotFast; slow is ok - no hurry!}
  100.  
  101.         strwidth := StringWidth(MyGetIndString(startbonusStrID));
  102.  
  103. { Draw a message and wait for click- this is a bit ugly. Consider other ways. }
  104.         SetPort(gSAT.wind.port);
  105.         SetRect(r, gSAT.offSizeH div 2 - strwidth div 2 - 5 + 2, gSAT.offSizeV div 2 + 35 + 2, gSAT.offSizeH div 2 + strwidth div 2 + 5 + 2, gSAT.offSizeV div 2 + 60 + 2); {offset by 2 pixels}
  106.         PaintRect(r);
  107.         SetRect(r, gSAT.offSizeH div 2 - strwidth div 2 - 5, gSAT.offSizeV div 2 + 35, gSAT.offSizeH div 2 + strwidth div 2 + 5, gSAT.offSizeV div 2 + 60);
  108.         EraseRect(r);
  109.  
  110.         MoveTo(gSAT.offSizeH div 2 - strwidth div 2, gSAT.offSizeV div 2 + 50);
  111.         DrawString(MyGetIndString(startbonusStrID)); {str 16: Click mouse for bonus level!}
  112.  
  113. {Wait until something happens}
  114.         FlushEvents(everyEvent, 0); { To forget events, like mouse clicks etc. }
  115.         repeat
  116.         until EventAvail(mDownMask + keyDownMask, er);
  117.  
  118. { Redraw to get rid of the message we just made. }
  119.         HQRedraw;
  120.     end; { SetupBonusLevel }
  121.  
  122. { Setup a new level. This is called when the game starts ans at each new level.}
  123.     procedure SetupLevel (level: integer);
  124.         var
  125.             p: point;
  126.             i: integer;
  127.             mp, oldmp: SpritePtr;
  128.             r: rect;
  129.             s: Str255;
  130.             er: EventRecord; {For EventAvail}
  131.             strwidth: integer;
  132.  
  133. { A routine to create a bunch of hearts }
  134.         procedure MakeHearts (howmany: integer);
  135.             var
  136.                 i: integer;
  137.                 mp: SpritePtr;
  138.         begin
  139.             for i := 1 to howmany do
  140.                 case SATRand(4) of
  141.                     0: 
  142.                         mp := SATNewSprite(-2, SATRand(gSAT.offSizeH - 112) + 17, 0, @SetupHeart);
  143.                     1: 
  144.                         mp := SATNewSprite(-2, SATRand(gSAT.offSizeH - 112) + 17, gSAT.offSizeV - 32, @SetupHeart);
  145.                     2: 
  146.                         mp := SATNewSprite(-2, 0, SATRand(gSAT.offSizeV - 32) + 17, @SetupHeart);
  147.                     3: 
  148.                         mp := SATNewSprite(-2, gSAT.offSizeH - xsize, SATRand(gSAT.offSizeV - 32) + 17, @SetupHeart);
  149.                 end;
  150.         end;
  151.  
  152.     begin { SetupLevel }
  153.  
  154. { Clear the sprite list }
  155.         while gSAT.sRoot <> nil do
  156.             SATKillSprite(gSAT.sRoot);
  157.  
  158. { Create all the sprites for the level, depending on the level number. }
  159.         case level of
  160.             1: 
  161.                 begin
  162.                     bonus := 250;
  163.                     MakeHearts(6);
  164.                     mp := SATNewSprite(-3, 10, 10, @SetupFlypaper);
  165.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, gSAT.offSizeV - 32, @SetupFlypaper);
  166.                 end;
  167.             2: 
  168.                 begin
  169.                     bonus := 300;
  170.                     MakeHearts(10);
  171.                     mp := SATNewSprite(-3, 10, 10, @SetupFlypaper);
  172.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, 20, @SetupFlypaper);
  173.                     mp := SATNewSprite(-3, 20, gSAT.offSizeV - 32, @SetupFlypaper);
  174.                 end;
  175.             3: 
  176.                 begin
  177.                     MakeHearts(12);
  178.                     bonus := 350;
  179.                     mp := SATNewSprite(-3, 5, 5, @SetupFlypaper);
  180.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, 5, @SetupFlypaper);
  181.                     mp := SATNewSprite(-3, 5, gSAT.offSizeV - 32, @SetupFlypaper);
  182.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, gSAT.offSizeV - 32, @SetupFlypaper);
  183.                 end;
  184.             4: 
  185.                 begin
  186.                     MakeHearts(12);
  187.                     bonus := 350;
  188.                     mp := SATNewSprite(-3, 5, 5, @SetupFlypaper);
  189.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, 5, @SetupFlypaper);
  190.                     mp := SATNewSprite(-3, 5, gSAT.offSizeV - 32, @SetupFlypaper);
  191.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, gSAT.offSizeV - 32, @SetupFlypaper);
  192.                     mp := SATNewSprite(-3, 5, (gSAT.offSizeV - 32) mod 2, @SetupFlypaper);
  193.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, (gSAT.offSizeV - 32) mod 2, @SetupFlypaper);
  194.                 end;
  195.             5: 
  196.                 begin
  197.                     MakeHearts(10);
  198.                     bonus := 380;
  199.                     mp := SATNewSprite(-3, 5, 5, @SetupFlypaper);
  200.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, 5, @SetupFlypaper);
  201.                     mp := SATNewSprite(-3, 5, gSAT.offSizeV - 32, @SetupFlypaper);
  202.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, gSAT.offSizeV - 32, @SetupFlypaper);
  203.                 end;
  204.             6: 
  205.                 begin
  206.                     MakeHearts(12);
  207.                     bonus := 420;
  208.                     mp := SATNewSprite(-3, 5, 5, @SetupFlypaper);
  209.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, 5, @SetupFlypaper);
  210.                     mp := SATNewSprite(-3, 5, gSAT.offSizeV - 32, @SetupFlypaper);
  211.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, gSAT.offSizeV - 32, @SetupFlypaper);
  212.                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, (gSAT.offSizeV - 32) mod 2, @SetupFlypaper);
  213.                 end;
  214.             otherwise
  215.                 begin
  216.                     MakeHearts(level * 2);
  217.                     bonus := 300 + 20 * level;
  218.                     for i := 0 to level - 1 do
  219.                         begin
  220.                             case SATRand(6) of
  221.                                 0: 
  222.                                     mp := SATNewSprite(-3, 5, 5, @SetupFlypaper);
  223.                                 1: 
  224.                                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, 5, @SetupFlypaper);
  225.                                 2: 
  226.                                     mp := SATNewSprite(-3, 5, 300, @SetupFlypaper);
  227.                                 3: 
  228.                                     mp := SATNewSprite(-3, gSAT.offSizeH - xsize - 32, gSAT.offSizeV - 32, @SetupFlypaper);
  229.                                 4: 
  230.                                     mp := SATNewSprite(-3, (gSAT.offSizeH - xsize - 32) div 2, 5, @SetupFlypaper);
  231.                                 5: 
  232.                                     mp := SATNewSprite(-3, (gSAT.offSizeH - xsize - 32), gSAT.offSizeV - 32, @SetupFlypaper);
  233.                             end; { case }
  234.                         end;
  235.                 end;
  236.         end;
  237.  
  238.         bonusLevelRunning := false;
  239.  
  240. { Reposition mouse to the center of the game area. }
  241.         p.h := 256;
  242.         p.v := 171;
  243.         SATSetMouse(p);
  244. { Make the player sprite. }
  245.         mp := SATNewSprite(2, (gSAT.offSizeH - xsize) div 2, gSAT.offSizeV div 2, @SetupPlayer);
  246.  
  247. {Fade out while we redraw!}
  248.         FadeScreen(20, true, fadeTo);
  249.  
  250. { Copy gSAT.backScreen to gSAT.offScreen to erase old sprites. }
  251.         CopyBits(gSAT.backScreen.port^.portBits, gSAT.offScreen.port^.portBits, gSAT.offScreen.port^.portRect, gSAT.offScreen.port^.portRect, srcCopy, nil);
  252.         HQRedraw;
  253.  
  254.         AddScore(0);
  255. { Do one frame of animation just to draw all the objects. }
  256.         SATRun(false); {false or features^^.PlotFast; slow is ok - no hurry!}
  257.  
  258.         if level = 1 then
  259.             s := MyGetIndString(startgameStrID)  {str 16: Click the mouse to start the game.}
  260.         else
  261.             s := stringof(MyGetIndString(startlevelStrID), level : 1, '.'); {str 17: Click the mouse to start level }
  262.  
  263.         if level = 1 then
  264.             strwidth := StringWidth(s)
  265.         else
  266.             strwidth := StringWidth(s);
  267.  
  268. { Draw a message and wait for click- this is a bit ugly. Consider other ways. }
  269.         SetPort(gSAT.wind.port);
  270.         SetRect(r, gSAT.offSizeH div 2 - strwidth div 2 - 5 + 2, gSAT.offSizeV div 2 + 35 + 2, gSAT.offSizeH div 2 + strwidth div 2 + 5 + 2, gSAT.offSizeV div 2 + 60 + 2); {offset by 2 pixels}
  271.         PaintRect(r);
  272.         SetRect(r, gSAT.offSizeH div 2 - strwidth div 2 - 5, gSAT.offSizeV div 2 + 35, gSAT.offSizeH div 2 + strwidth div 2 + 5, gSAT.offSizeV div 2 + 60);
  273.         EraseRect(r);
  274.  
  275.         MoveTo(gSAT.offSizeH div 2 - strwidth div 2, gSAT.offSizeV div 2 + 50);
  276.         DrawString(s);
  277.  
  278.         FadeScreen(20, false, fadeTo);
  279.  
  280. {Wait until something happens}
  281.         FlushEvents(EveryEvent, 0); { To forget events, like mouse clicks etc. }
  282.         repeat
  283.         until EventAvail(mDownMask + keyDownMask, er);
  284.  
  285. { Redraw to get rid of the message we just made. }
  286.         HQRedraw;
  287.     end; { SetupLevel }
  288.  
  289. { Start a new game. Initialize level, score, number of lives, and call setuplevel to make the first level. }
  290.     procedure StartGame;
  291.     begin
  292.         ZeroScore;
  293.         level := 1;
  294.  
  295.         bonusesCollected := 0;
  296.  
  297.         SetupLevel(level);
  298.     end;
  299.  
  300. { Game Over procedure. Draw "Game Over" text, check high scores. }
  301.  
  302.     procedure DoGameOver;
  303.         var
  304. { Variables for the Game Over-box }
  305.             theRect, theRect2: rect;
  306.             thePict: Handle;
  307.             bredd, i: integer;
  308.             dx, dy: integer;
  309.             time: longint;
  310.     begin
  311.         SetMenuItemText(GameMenu, Pause, MyGetIndString(pauseStrID)); {str 18: Pause}
  312. { Game Over display! }
  313.         SetPort(gSAT.wind.port);
  314.         if gSAT.colorFlag and (gSAT.initDepth <> 1) then
  315.             thePICT := GetResource('PICT', 129)
  316.         else
  317.             thePICT := GetResource('PICT', 128);
  318.         theRect := PicHandle(thePICT)^^.picFrame;
  319.         theRect.right := theRect.right - theRect.left;
  320.         theRect.bottom := theRect.bottom - theRect.top;
  321.         theRect.top := 0;
  322.         theRect.left := 0;
  323.  
  324.         dx := (gSAT.offSizeH - (theRect.right - theRect.left)) div 2 - theRect.left;
  325.         dy := (gSAT.offSizeV - (theRect.bottom - theRect.top)) div 2 - theRect.top;
  326.         OffsetRect(theRect, dx, dy);
  327.  
  328.         bredd := theRect.right - theRect.left;
  329.         theRect2 := theRect;
  330.  
  331.         i := 1;
  332.         repeat
  333.             time := TickCount;
  334.             theRect.right := theRect2.right - bredd * (80 - i) div 160;
  335.             theRect.left := theRect2.left + bredd * (80 - i) div 160;
  336.             DrawPicture(PicHandle(thePICT), TheRect);
  337.             i := i + TickCount - time;
  338.         until i >= 80;
  339.  
  340.         SetPort(gSAT.offScreen.port);
  341.         DrawPicture(PicHandle(thePICT), TheRect);
  342.         SetPort(gSAT.wind.port);
  343.  
  344.         InvalRect(theRect);
  345.  
  346.         SATSoundShutUp; { Dispose of sound channel }
  347.  
  348.         FlushEvents(everyEvent, 0); { To forget events, like mouse clicks etc. }
  349.         ShowCursor;
  350.         SATShowMBar(nil);
  351.  
  352.         UpdateHigh; { Game over, was it high score? }
  353.     end;
  354.  
  355.  
  356. { This routine is the game driver. It calls the "Animator" package until the game ends or is paused. }
  357. { I also read the keyboard here. This could optionally be moved to the "player object" module. }
  358.  
  359.     procedure MoveIt;
  360.         var
  361.             fr, tr, r: Rect;
  362.             pt: Point;
  363.             t, l: longint;
  364.             theEvent: EventRecord; { för att testa musklick }
  365. { To check for key clicks with GetKeys:  - no longer used. km: KeyMap;}
  366.             hasEvent: Boolean;
  367.             ignore: OSerr;
  368.     begin
  369.         stillrunning := true; { A flag that tells whether or not to quit this routine. }
  370.  
  371.         HideCursor; { NOTE: No matter how we leave the MoveIt procedure, we should ShowCursor. }
  372.  
  373.         pt.h := 256;
  374.         pt.v := 171;
  375.         SATSetMouse(pt);
  376.         SATHideMBar(gSAT.wind.port);
  377.         HQRedraw;
  378.  
  379. { Main loop! Keep running until the game is paused or ends. }
  380.         while stillrunning = true do
  381.             begin
  382.                 t := TickCount;
  383.                 SetPort(gSAT.offScreen.port);
  384.  
  385. {Reset booleans that will be set by the sprites.}
  386.                 bonusObjectRunning := false;
  387.                 levelCompleted := true;
  388.  
  389. { Here is the real heart of the loop: call Animator once per loop. It will call all the objects. }
  390.                 SATRun(features^^.plotFast);
  391. {SATSoundEvents; No longer needed - included in SATRun!}
  392.  
  393. { All the rest of the main loop is game specific, next level, bonus handling, etc. }
  394.  
  395. {Decrease bonus. Out of bonus? Does not apply to bonus levels.}
  396.                 if not bonusLevelRunning then
  397.                     if not bonusObjectRunning or features^^.macho then
  398.                         if bonus > 0 then
  399.                             begin
  400.                                 bonus := bonus - 1;
  401.                                 if bonus mod 10 = 0 then
  402.                                     begin
  403.                                         AddScore(0);
  404.                                         if features^^.macho then
  405.                                             if bonus < 110 then
  406.                                                 SATSoundPlay(TickSndH, 0, false);
  407.                                     end
  408.                                 else if features^^.macho then
  409.                                     if bonus < 26 then
  410.                                         if bonus mod 5 = 0 then
  411.                                             SATSoundPlay(TickSndH, 0, false);
  412.                             end
  413.                         else if features^^.macho then
  414.                             stillrunning := false;
  415.  
  416.                 if levelCompleted then{(batchcount < 1)}
  417.         {All hearts collected?}
  418.                     begin
  419.                         SATSoundShutUp;
  420.  
  421.                         SATSoundPlay(sadarSndH, 0, true);
  422.                         repeat
  423.                             SATSoundEvents
  424.                         until SATSoundDone;
  425.  
  426. {If it isn't a bonus level, we should give the player the bonus remaining}
  427.                         if not bonusLevelRunning then
  428.                             if bonus > 0 then
  429.                                 while bonus > 0 do
  430.                                     begin
  431.                                         bonus := bonus - 10;
  432.  
  433.                                         SATSoundPlay(KlounkSndH, 0, true);
  434.                                         repeat
  435.                                             SATSoundEvents
  436.                                         until SATSoundDone;
  437.  
  438.                                         if bonus < 0 then
  439.                                             begin
  440.                                                 l := bonus;
  441.                                                 bonus := 0;
  442.                                                 AddScoreS(10 + l); {A special synchronous version of AddScore}
  443.                                             end
  444.                                         else
  445.                                             AddScoreS(10); { Bonus! }
  446.                                     end { if bonus > 0 }
  447.                             else if features^^.macho then
  448.                                 stillrunning := false; { If no bonus, game over }
  449.  
  450. {Level finished? Do we want a new level?}
  451.                         if (stillrunning and features^^.macho) or (level < 3) then
  452.                             if bonusesCollected >= kBonusLevelTresh then
  453.                                 begin
  454.                                     SetupBonusLevel(level);
  455.                                     AddScoreS(0); {To update the level number}
  456.                                     bonusesCollected := bonusesCollected - kBonusLevelTresh;
  457.                                 end
  458.                             else
  459.                                 begin
  460.                                     level := level + 1;
  461.                                     SetupLevel(level);
  462.                                     AddScoreS(0); {To update the level number}
  463.                                 end
  464.                         else
  465.                             stillrunning := false;
  466.                     end; {if (batchcount < 1)}
  467.  
  468. { Check for keys being pressed }
  469.                 if features^^.allowBG then { if we are allowed to use the normal method }
  470.                     begin
  471.                         SystemTask;
  472. { Replaced the following call by WaitNextEvent if you want to be modern (but less backwards compatible). :-) }
  473.                         hasEvent := GetNextEvent(keyDownMask, theEvent)
  474.                     end
  475.                 else {Otherwise, use the faster GetOSEvent}
  476.                     begin
  477.                         hasEvent := GetOSEvent(keyDownMask, theEvent)
  478.                     end;
  479.  
  480. {If there was a keydown, see if it was one of the menu options that we support when running.}
  481.                 if hasEvent then { there was a keydown }
  482.                     if BitAnd(theEvent.modifiers, cmdKey) <> 0 then
  483.                         begin
  484.                             case char(BitAnd(theEvent.message, charCodeMask)) of
  485.                                 'p': 
  486.                                     begin
  487.                                         PauseFlag := true;
  488.                                         SATSoundShutUp; { Dispose of sound channel }
  489.                                         ShowCursor;
  490.                                         SATShowMBar(nil);
  491.                                         FlushEvents(6 + 8, 0); { In order to forget the cmd-p }
  492.                                         SetMenuItemText(GameMenu, Pause, MyGetIndString(resumeStrID)); {str 19: Resume}
  493.                                         exit(MoveIt);
  494.                                     end;
  495.                                 '.': 
  496.                                     stillRunning := false;
  497.                                 'q': 
  498.                                     begin
  499.                                         stillRunning := false;
  500.                                         SkelWhoa;
  501.                                     end;
  502.                                 's': 
  503.                                     begin
  504.                                         DoGameMenu(sound);
  505.                                     end;
  506.                                 otherwise
  507.                                     ;
  508.                             end; {case}
  509.                         end
  510.                     else if BitAnd(theEvent.message, charCodeMask) = 27 then {ESC}
  511.                         stillRunning := false;
  512.  
  513. { Delay, using TickCount so it doesn't matter how fast our Mac is. }
  514.                 while ((TickCount - t) < 3) do
  515.                     ;
  516.  
  517.             end; { while stillrunning (main loop) }
  518.  
  519.         DoGameOver;
  520.  
  521.         FlushEvents(mouseDown + keyDown, 0); { In order to forget the cmd-p }
  522.     end;
  523.  
  524. {Almost same as SATRedraw, but not black borders}
  525.     procedure HQRedraw;
  526.         var
  527.             r: Rect;
  528.             savePort: SATPort;
  529.     begin
  530.         SATGetPort(savePort);
  531.         SATSetPortScreen;
  532.  
  533.         if gSAT.colorFlag then
  534.             RGBForeColor(fadeTo); {Same color as we fade to!}
  535.  
  536.         SetRect(r, gSAT.wind.port^.portRect.left, gSAT.wind.port^.portRect.top, 0, gSAT.wind.port^.portRect.bottom);
  537.         PaintRect(r);
  538.         SetRect(r, 0, gSAT.wind.port^.portRect.top, gSAT.offSizeH, 0);
  539.         PaintRect(r);
  540.         SetRect(r, 0, gSAT.offSizeV, gSAT.wind.port^.portRect.right, gSAT.wind.port^.portRect.bottom);
  541.         PaintRect(r);
  542.         SetRect(r, gSAT.offSizeH, gSAT.wind.port^.portRect.top, gSAT.wind.port^.portRect.right, gSAT.offSizeV);
  543.         PaintRect(r);
  544.  
  545.         SetRect(r, 0, 0, gSAT.offSizeH, gSAT.offSizeV);
  546.  
  547.         ForeColor(blackColor);
  548.         CopyBits(gSAT.offScreen.port^.portBits, gSAT.wind.port^.portBits, r, r, srcCopy, nil);
  549.         SATSetPort(savePort);
  550.     end;
  551.  
  552. {We used to draw the background ourselves rather than using a simple backdrop PICT, to save space and to get}
  553. {the dithered background. However, using the shades in the object drawing part of ClarisWorks, I can make PICT}
  554. {resources that are fairly small, so I use that instead now.}
  555. {Thus, DrawBackground ONLY draws the trees!}
  556.     procedure DrawBackground;
  557.         var
  558.             ph: PicHandle;
  559.             ignore: OSErr;
  560.             col: RGBColor;
  561.             thinr, r: Rect;
  562.             i, j: integer;
  563.  
  564.             posH, posV, scale, height, width: longint; {For scaling the trees}
  565.     begin
  566.         SATSetPortBackScreen;
  567.         SetRect(r, 0, 0, gSAT.offSizeH, gSAT.offSizeV);
  568.  
  569.         if gSAT.colorFlag then
  570.             RGBForeColor(fadeTo); {Same color as we fade to!}
  571.         PaintRect(r);
  572.         ForeColor(blackColor);
  573.  
  574.         SATDrawPicts(132, 133);
  575.         SATSetPortBackScreen;
  576.  
  577. {Draw trees using PICTs!}
  578.  
  579. {First get the right PICT}
  580.         if gSAT.initDepth = 1 then
  581.             begin
  582.                 ph := GetPicture(135); {bw tree PICT}
  583.             end
  584.         else
  585.             begin
  586.                 ph := GetPicture(134); {color tree PICT}
  587.             end;
  588.         if ph = nil then
  589.             exit(DrawBackground);
  590.  
  591. {Scale by ph^^.picframe}
  592.         for i := 0 to 10 do
  593. {For more trees: for j := i to 4 do}
  594.             begin
  595.                 posH := SATRand(gSAT.offSizeH);
  596.                 posV := gSAT.offSizeV div 2 + longint(i) * i * gSAT.offSizeV div 300;
  597.  
  598.                 scale := (posV - gSAT.offSizeV div 4) div 17;
  599.                 height := scale * (ph^^.picframe.bottom - ph^^.picframe.top) div 40;
  600.                 width := scale * (ph^^.picframe.right - ph^^.picframe.left) div 40;
  601.  
  602.                 r.top := posV - height;
  603.                 r.bottom := posV;
  604.                 r.right := posH + width;
  605.                 r.left := posH;
  606.  
  607.                 DrawPicture(ph, r);
  608.             end;
  609.  
  610.         ReleaseResource(handle(ph));
  611.  
  612.         CopyBits(gSAT.backScreen.port^.portBits, gSAT.offScreen.port^.portBits, gSAT.backScreen.port^.portRect, gSAT.backScreen.port^.PortRect, srcCopy, nil);
  613.         SATSetPortScreen;
  614. {HQRedraw;}
  615. {CopyBits(gSAT.backScreen^.portBits, gSAT.wind^.portBits, gSAT.backScreen^.portRect, gSAT.backScreen^.PortRect, srcCopy + ditherCopy, nil);}
  616.     end;
  617.  
  618.  
  619.     procedure GameWindUpdate;
  620.         var
  621.             s: str255;
  622.             r: Rect;
  623.             crsr: CursHandle;
  624.     begin
  625. {When the depth has changed, the game wind will get an update event,}
  626. {so let's give SAT a chance to update itself before updating!}
  627.  
  628.         crsr := GetCursor(WatchCursor);
  629.         SetCursor(crsr^^);
  630.         if SATDepthChangeTest then
  631.             begin
  632.                 DrawBackground;    {Redraw trees}
  633.             end;
  634.         ReleaseResource(handle(crsr));
  635.         InitCursor;
  636.  
  637.         HQRedraw;
  638.         AddScore(0);
  639.     end;
  640.  
  641.     procedure DoGameMenu (item: integer);
  642.     begin
  643.         case (item) of
  644.             run: 
  645.                 begin
  646. { Test if we have Color QD, and if so, test bit depth! Alert if features^^.PlotFast.}
  647.                     if SATDepthChangeTest then {Update if necessary}
  648.                         DrawBackground;
  649.                     if not ((gSAT.initDepth = 1) or (gSAT.initDepth = 4) or (gSAT.initDepth = 8)) and features^^.PlotFast then
  650.                         begin
  651.                             SATReportStr(MyGetIndString(pleaseuncheckStrID));
  652. {str 23: Please uncheck ''Fast animation'' or set the monitor to 1-, 4- or 8-bit mode in the Control Panel.}
  653.                             exit(DoGameMenu);
  654.                         end;
  655.                     if pauseFlag then
  656.                         if SATQuestionStr(MyGetIndString(endStrID)) then {str 24: End the Current game?}
  657.                             DoGameMenu(abort)
  658.                         else
  659.                             exit(DoGameMenu);
  660.                     DisableItem(gameMenu, macho);
  661.                     ShowWindow(gSAT.wind.port);
  662.                     SelectWindow(gSAT.wind.port);
  663.                     StartGame;
  664.                     GameWindUpdate;
  665.                     MoveIt;
  666.                     if not pauseFlag then
  667.                         EnableItem(GameMenu, macho);
  668.                 end;
  669.             sound: 
  670.                 begin
  671.                     features^^.sound := not features^^.sound;
  672.                     CheckItem(GameMenu, sound, features^^.sound);
  673.                     if features^^.sound then { Tell the sound package our settings, so we don't have to bother. }
  674.                         SATSoundOn
  675.                     else
  676.                         SATSoundOff;
  677.                     ChangedResource(handle(features));
  678.                 end;
  679.             macho: 
  680.                 begin
  681.                     features^^.macho := not features^^.macho;
  682.                     CheckItem(GameMenu, macho, features^^.macho);
  683.                     ChangedResource(handle(features));
  684.                 end;
  685.             AllowBG: 
  686.                 begin
  687.                     features^^.AllowBG := not features^^.AllowBG;
  688.                     CheckItem(GameMenu, AllowBG, features^^.AllowBG);
  689.                     ChangedResource(handle(features));
  690.                 end;
  691.             FastAnimation: 
  692.                 begin
  693.                     features^^.PlotFast := not features^^.PlotFast;
  694.                     CheckItem(GameMenu, FastAnimation, features^^.PlotFast);
  695.                     ChangedResource(handle(features));
  696.                 end;
  697.             pause: 
  698.                 begin
  699. { Pause is only interesting here as "resume". }
  700.                     if pauseFlag then
  701.                         begin
  702. { Test if we have Color QD, and if so, test bit depth! Alert if features^^.PlotFast.}
  703.                             if SATDepthChangeTest then {Update if necessary}
  704.                                 DrawBackground;
  705.                             if not ((gSAT.initDepth = 1) or (gSAT.initDepth = 4) or (gSAT.initDepth = 8)) and features^^.PlotFast then
  706.                                 begin
  707.                                     SATReportStr(MyGetIndString(pleaseuncheckStrID)); {str 23}
  708.                                     exit(DoGameMenu);
  709.                                 end;
  710.                             SetMenuItemText(GameMenu, pause, MyGetIndString(pauseStrID)); {str 18}
  711.                             pauseFlag := false;
  712.                             ShowWindow(gSAT.wind.port);
  713.                             SelectWindow(gSAT.wind.port);
  714.                             GameWindUpdate;
  715.                             MoveIt;
  716.                             if not pauseFlag then
  717.                                 EnableItem(GameMenu, macho);
  718.                         end;
  719.                 end;
  720.             abort: 
  721.                 begin
  722.                     if pauseFlag then
  723.                         begin
  724.                             SetMenuItemText(GameMenu, Pause, MyGetIndString(pauseStrID)); {str 18}
  725.                             DoGameOver;
  726.                             pauseFlag := false;
  727.                             EnableItem(GameMenu, macho);
  728.                         end
  729.                 end;
  730.         end;
  731.     end;
  732.  
  733.     procedure GameWindMouse (thePoint: Point; theTime: longint; theMods: integer; myProc: ProcPtr);
  734.     begin
  735.         if pauseFlag then
  736.             DoGameMenu(pause)
  737.         else
  738.             DoGameMenu(run);
  739.     end;
  740.  
  741.     procedure GameWindIdle;
  742.     begin
  743.     end;
  744.  
  745.     procedure GameWindClose;
  746.     begin
  747.     end;
  748.  
  749.     procedure GameWindInit;
  750.     begin
  751. { Tell TransSkel to handle all the tedious things with gSAT.wind. }
  752.         dummy := SkelWindow(gSAT.wind.port, @GameWindMouse, nil, @GameWindUpdate, nil, @GameWindClose, nil, @GameWindIdle, false);
  753.     end;
  754.  
  755. end.